Environment Configuration
**Referenced Files in This Document** - [README.md](file://README.md) - [.gitignore](file://.gitignore) - [cloudflare-pages.toml](file://cloudflare-pages.toml) - [netlify.toml](file://netlify.toml) - [wrangler.jsonc](file://wrangler.jsonc) - [worker.js](file://worker.js) - [package.json](file://package.json) - [.eleventy.js](file://.eleventy.js) - [tina/config.ts](file://tina/config.ts)Table of Contents
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
Introduction
This document explains how environment configuration and secrets are managed across development, staging, and production deployments for this project. It covers the environment variable structure used by the Cloudflare Worker, Eleventy build pipeline, and optional CMS tooling. It also documents the differences between deployment targets, secure handling of secrets, integration with external services (GitHub OAuth, Google Sheets API, email), and practical guidance for configuration validation, migration, and disaster recovery.
Project Structure
The project uses:
- A Cloudflare Worker to serve member authentication, magic-link email dispatch, and selected APIs.
- An Eleventy static site built into the _site directory and served by the Worker’s assets binding.
- Optional CMS tooling (TinaCMS) for local content editing.
- Deployment configurations for Cloudflare Pages and Netlify (legacy or complementary), and Wrangler for Workers.
graph TB
Dev["Developer Machine"] --> Eleventy["Eleventy Build (_site)"]
Eleventy --> Worker["Cloudflare Worker (worker.js)"]
Worker --> Assets["Assets Binding (ASSETS)"]
Worker --> External_GitHub["GitHub OAuth API"]
Worker --> External_Resend["Resend Email API"]
Worker --> External_Sheets["Google Sheets API"]
Dev --> Netlify["Netlify Config (netlify.toml)"]
Dev --> CFPages["Cloudflare Pages Config (cloudflare-pages.toml)"]
Dev --> Wrangler["Wrangler Config (wrangler.jsonc)"]
Diagram sources
- [worker.js:301-321](file://worker.js#L301-L321)
- [wrangler.jsonc:9-12](file://wrangler.jsonc#L9-L12)
- [netlify.toml:1-26](file://netlify.toml#L1-L26)
- [cloudflare-pages.toml:1-17](file://cloudflare-pages.toml#L1-L17)
Section sources
- [package.json:5-12](file://package.json#L5-L12)
- [wrangler.jsonc:1-35](file://wrangler.jsonc#L1-L35)
- [worker.js:301-321](file://worker.js#L301-L321)
- [netlify.toml:1-26](file://netlify.toml#L1-L26)
- [cloudflare-pages.toml:1-17](file://cloudflare-pages.toml#L1-L17)
Core Components
- Cloudflare Worker (worker.js): Implements member authentication, magic-link email dispatch via Resend, Google Sheets polling API, and legacy GitHub OAuth for CMS integrations. Reads secrets and bindings from the runtime environment.
- Wrangler configuration (wrangler.jsonc): Declares the Worker entrypoint, assets binding, compatibility flags, and KV namespace bindings for member auth.
- Eleventy (.eleventy.js): Controls build outputs, watch targets, and production transforms; reads NODE_ENV to enable minification.
- Deployment configs: netlify.toml and cloudflare-pages.toml define build commands and environment variables for static hosting platforms.
- Git and secret exclusion: .gitignore excludes generated and sensitive files, including Wrangler environment files and dotenv files.
Section sources
- [worker.js:1-321](file://worker.js#L1-L321)
- [wrangler.jsonc:1-35](file://wrangler.jsonc#L1-L35)
- [.eleventy.js:242-261](file://.eleventy.js#L242-L261)
- [netlify.toml:1-26](file://netlify.toml#L1-L26)
- [cloudflare-pages.toml:1-17](file://cloudflare-pages.toml#L1-L17)
- [.gitignore:14-20](file://.gitignore#L14-L20)
Architecture Overview
The runtime environment is composed of:
- Secrets stored in the Worker runtime (via Wrangler secrets).
- KV namespaces bound in the Worker for membership gating.
- Static assets served via the ASSETS binding.
- External service integrations invoked by the Worker.
sequenceDiagram
participant Browser as "Browser"
participant Worker as "worker.js"
participant KV as "KV Namespaces"
participant Resend as "Resend API"
participant Sheets as "Google Sheets API"
Browser->>Worker : POST /alliance/login/ (email)
Worker->>KV : Lookup member : <email>
alt Approved member
Worker->>KV : Put token : <hex>, TTL=900s
Worker->>Resend : Send magic-link email (Bearer <RESEND_API_KEY>)
Resend-->>Worker : 200 OK
else Not approved or missing config
Worker-->>Browser : Redirect with status/sent
end
Browser->>Worker : GET /alliance/verify/?token=<hex>
Worker->>KV : Get token : <hex>
alt Valid token
Worker->>KV : Delete token : <hex>
Worker-->>Browser : 302 with session cookie
else Expired/invalid
Worker-->>Browser : Redirect with error
end
Browser->>Worker : GET /api/polling.json?state=(federal|sa)
Worker->>Sheets : Fetch spreadsheet values (GOOGLE_SHEETS_ID, GOOGLE_SHEETS_API_KEY)
Sheets-->>Worker : JSON values
Worker-->>Browser : JSON polling data
Diagram sources
- [worker.js:77-177](file://worker.js#L77-L177)
- [worker.js:233-276](file://worker.js#L233-L276)
Section sources
- [worker.js:77-177](file://worker.js#L77-L177)
- [worker.js:233-276](file://worker.js#L233-L276)
Detailed Component Analysis
Environment Variables and Secrets
Secrets are stored in the Worker runtime and never committed to the repository. They are set via Wrangler CLI and accessed inside the Worker.
-
Worker secrets (set via Wrangler CLI):
- SESSION_SECRET: HMAC key for signed session tokens.
- RESEND_API_KEY: API key for sending magic-link emails.
- GOOGLE_SHEETS_ID: Google Sheets document identifier.
- GOOGLE_SHEETS_API_KEY: Public API key for Sheets read access.
- GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET: Legacy GitHub OAuth for CMS integrations.
-
CMS secrets (local-only):
- TINA_PUBLIC_CLIENT_ID and TINA_TOKEN: Used by TinaCMS when building admin assets locally.
-
KV namespaces (bound in wrangler.jsonc):
- MEMBER_EMAILS: Approved member email lookup.
- MAGIC_TOKENS: One-time login tokens with TTL.
-
Build-time environment:
- NODE_VERSION: Set in deployment configs for Pages/Netlify.
- NODE_ENV: Controls Eleventy production transforms.
Section sources
- [README.md:497-521](file://README.md#L497-L521)
- [worker.js:4-10](file://worker.js#L4-L10)
- [wrangler.jsonc:28-34](file://wrangler.jsonc#L28-L34)
- [tina/config.ts:3-9](file://tina/config.ts#L3-L9)
- [netlify.toml:5-6](file://netlify.toml#L5-L6)
- [cloudflare-pages.toml:10-11](file://cloudflare-pages.toml#L10-L11)
- [.eleventy.js:242-261](file://.eleventy.js#L242-L261)
Environment Variable Usage in the Worker
- Session management:
- Uses SESSION_SECRET to sign/verify session tokens.
- Sets HttpOnly Secure SameSite cookies for session persistence.
- Email delivery:
- Uses RESEND_API_KEY to send magic-link emails.
- Member gating:
- Uses MEMBER_EMAILS and MAGIC_TOKENS KV namespaces.
- Polling API:
- Uses GOOGLE_SHEETS_ID and GOOGLE_SHEETS_API_KEY to fetch live polling data.
- GitHub OAuth:
- Uses GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET to initiate and complete OAuth for CMS integrations.
flowchart TD
Start(["Worker fetch(request, env)"]) --> Route["Match route"]
Route --> |/alliance/login/ POST| Login["Validate email<br/>Store token in KV<br/>Send email via Resend"]
Route --> |/alliance/verify/ GET| Verify["Lookup token in KV<br/>Delete token<br/>Issue session cookie"]
Route --> |/api/polling.json GET| Sheets["Fetch from Google Sheets using IDs/API key"]
Route --> |/api/auth*/...| OAuth["Legacy GitHub OAuth (start/callback)"]
Route --> |Other| Assets["Serve static assets via ASSETS"]
Login --> End(["Response"])
Verify --> End
Sheets --> End
OAuth --> End
Assets --> End
Diagram sources
- [worker.js:301-321](file://worker.js#L301-L321)
- [worker.js:97-147](file://worker.js#L97-L147)
- [worker.js:153-177](file://worker.js#L153-L177)
- [worker.js:233-276](file://worker.js#L233-L276)
- [worker.js:193-227](file://worker.js#L193-L227)
Section sources
- [worker.js:301-321](file://worker.js#L301-L321)
- [worker.js:97-147](file://worker.js#L97-L147)
- [worker.js:153-177](file://worker.js#L153-L177)
- [worker.js:233-276](file://worker.js#L233-L276)
- [worker.js:193-227](file://worker.js#L193-L227)
Configuration Differences Across Environments
- Development:
- Local Eleventy preview: run the dev script to serve content locally.
- Optional CMS: set TINA_PUBLIC_CLIENT_ID and TINA_TOKEN when generating admin assets locally.
- Secrets: not applicable for local Eleventy; Worker secrets are set via Wrangler CLI during deployment.
- Staging:
- Use Wrangler to deploy to a staging account or namespace; configure secrets and KV namespaces accordingly.
- Validate routes and integrations against staging credentials.
- Production:
- Deploy via Wrangler to the production Worker.
- Ensure KV namespaces are created and bound, and all secrets are set.
- Confirm external service credentials are valid and rate limits are considered.
Section sources
- [package.json:8-12](file://package.json#L8-L12)
- [tina/config.ts:3-9](file://tina/config.ts#L3-L9)
- [wrangler.jsonc:17-26](file://wrangler.jsonc#L17-L26)
- [README.md:497-521](file://README.md#L497-L521)
.gitignore Patterns and Sensitive File Exclusions
- Generated and temporary files:
- node_modules/**, _site/, .DS_Store, *.log
- Wrangler and dotenv:
- .wrangler, .dev.vars* (keep .dev.vars.example), .env* (keep .env.example)
- Obsidian vault:
- Per-user Obsidian workspace and cache files
These patterns prevent committing secrets, generated artifacts, and developer-specific state.
Section sources
- [.gitignore:1-20](file://.gitignore#L1-L20)
Integration with External Services
- GitHub OAuth (legacy CMS):
- Starts OAuth with GITHUB_CLIENT_ID and redirects to callback; exchanges code for access token using GITHUB_CLIENT_SECRET.
- Google Sheets API:
- Fetches polling data using GOOGLE_SHEETS_ID and GOOGLE_SHEETS_API_KEY.
- Email via Resend:
- Sends magic-link emails using RESEND_API_KEY.
sequenceDiagram
participant CMS as "Sveltia/Decap CMS"
participant Worker as "worker.js"
participant GH as "GitHub OAuth API"
participant Resend as "Resend API"
CMS->>Worker : OPTIONS /api/auth
Worker-->>CMS : Preflight response
CMS->>Worker : GET /api/auth
Worker->>GH : Redirect to authorize with GITHUB_CLIENT_ID
GH-->>Worker : Redirect with code
CMS->>Worker : GET /api/auth/callback
Worker->>GH : Exchange code for access token (GITHUB_CLIENT_SECRET)
GH-->>Worker : Token
Worker-->>CMS : HTML with token posted to opener
Diagram sources
- [worker.js:183-227](file://worker.js#L183-L227)
Section sources
- [worker.js:183-227](file://worker.js#L183-L227)
Secret Management Best Practices
- Never commit secrets:
- Use .gitignore to exclude Wrangler and dotenv files.
- Use Worker secrets:
- Store sensitive values via Wrangler CLI; access via env in the Worker.
- Scope secrets:
- Limit to required services (Resend, Sheets, GitHub OAuth).
- Rotation and least privilege:
- Rotate secrets regularly; grant minimal permissions to external services.
- Validation:
- Add checks for missing secrets and return appropriate errors.
- Backup and recovery:
- Maintain a secure inventory of secrets and bindings; document creation steps for KV namespaces.
Section sources
- [.gitignore:14-20](file://.gitignore#L14-L20)
- [wrangler.jsonc:28-34](file://wrangler.jsonc#L28-L34)
- [worker.js:70-75](file://worker.js#L70-L75)
Practical Examples
- Setting up Worker secrets:
- Use Wrangler CLI to set SESSION_SECRET, RESEND_API_KEY, GOOGLE_SHEETS_ID, GOOGLE_SHEETS_API_KEY, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET.
- Building and deploying:
- Build site and deploy via Wrangler; confirm assets binding serves static content.
- Validating configuration:
- Check KV namespaces are bound and populated; verify Resend and Sheets credentials; test OAuth flow.
- Troubleshooting:
- Missing secrets: Worker returns a 503 indicating KV namespaces not configured.
- Invalid or expired token: Redirect with appropriate error query parameters.
- Missing Google Sheets credentials: API returns a 503 indicating service misconfiguration.
Section sources
- [README.md:497-521](file://README.md#L497-L521)
- [worker.js:70-75](file://worker.js#L70-L75)
- [worker.js:244-246](file://worker.js#L244-L246)
Dependency Analysis
- Build pipeline:
- Eleventy builds static content into _site; Wrangler serves it via ASSETS binding.
- Runtime dependencies:
- Worker depends on secrets and KV namespaces for authentication and on external APIs for email and data.
- Deployment targets:
- Netlify and Cloudflare Pages configs define build commands and environment variables for static hosting.
graph LR
Eleventy[".eleventy.js"] --> Site["_site"]
Site --> Wrk["worker.js"]
Wrk --> AS["ASSETS binding"]
Wrk --> Sec["Worker Secrets"]
Wrk --> KV["KV Namespaces"]
Wrk --> Ext1["Resend API"]
Wrk --> Ext2["Google Sheets API"]
Wrk --> Ext3["GitHub OAuth API"]
Diagram sources
- [.eleventy.js:267-283](file://.eleventy.js#L267-L283)
- [wrangler.jsonc:9-12](file://wrangler.jsonc#L9-L12)
- [worker.js:301-321](file://worker.js#L301-L321)
Section sources
- [.eleventy.js:267-283](file://.eleventy.js#L267-L283)
- [wrangler.jsonc:9-12](file://wrangler.jsonc#L9-L12)
- [worker.js:301-321](file://worker.js#L301-L321)
Performance Considerations
- Static asset caching:
- Netlify sets long-lived cache headers for assets.
- API caching:
- Polling API sets cache-control headers to balance freshness and performance.
- Build-time minification:
- Eleventy minifies HTML in production mode.
Section sources
- [netlify.toml:22-26](file://netlify.toml#L22-L26)
- [worker.js:234-238](file://worker.js#L234-L238)
- [.eleventy.js:242-261](file://.eleventy.js#L242-L261)
Troubleshooting Guide
- Missing secrets or KV namespaces:
- Worker returns a 503 indicating KV namespaces not configured; ensure bindings and secrets are set.
- Email delivery failures:
- Verify RESEND_API_KEY and Resend configuration; check network and rate limits.
- Google Sheets API errors:
- Confirm GOOGLE_SHEETS_ID and GOOGLE_SHEETS_API_KEY; validate sheet visibility and range.
- OAuth issues:
- Ensure GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET are set; verify redirect URIs and scopes.
- Build failures:
- Confirm NODE_VERSION matches deployment target; check Eleventy filters and transforms.
Section sources
- [worker.js:70-75](file://worker.js#L70-L75)
- [worker.js:244-246](file://worker.js#L244-L246)
- [netlify.toml:5-6](file://netlify.toml#L5-L6)
- [cloudflare-pages.toml:10-11](file://cloudflare-pages.toml#L10-L11)
Conclusion
Environment configuration in this project centers on secure Worker secrets, KV-backed membership gating, and external service integrations. By following the documented setup, validation, and troubleshooting steps, teams can confidently manage configuration across development, staging, and production while maintaining strong security and operational reliability.
Appendices
Environment Variables Reference
- Worker secrets:
- SESSION_SECRET, RESEND_API_KEY, GOOGLE_SHEETS_ID, GOOGLE_SHEETS_API_KEY, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
- CMS (local-only):
- TINA_PUBLIC_CLIENT_ID, TINA_TOKEN
- Build/runtime:
- NODE_VERSION, NODE_ENV
Section sources
- [README.md:497-521](file://README.md#L497-L521)
- [tina/config.ts:3-9](file://tina/config.ts#L3-L9)
- [netlify.toml:5-6](file://netlify.toml#L5-L6)
- [cloudflare-pages.toml:10-11](file://cloudflare-pages.toml#L10-L11)
- [.eleventy.js:242-261](file://.eleventy.js#L242-L261)